1 /*
2  * Hunt - a framework for web and console application based on Collie using Dlang development
3  *
4  * Copyright (C) 2015-2017  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.application.dispatcher;
13 
14 import hunt.routing;
15 import hunt.http.request;
16 import hunt.http.response;
17 
18 import hunt.application.controller;
19 import hunt.application.config;
20 
21 import hunt.security.acl.Manager;
22 
23 import collie.utils.exception;
24 import collie.codec.http;
25 
26 import std.stdio;
27 
28 import std.exception;
29 import hunt.application.application;
30 import std.parallelism;
31 import hunt.security.acl.User;
32 
33 class Dispatcher
34 {
35     this()
36     {
37         this._router = new Router;
38         this._router.setConfigPath(Config.path);
39     }
40 
41     public
42     {
43         void dispatch(Request request) nothrow
44         {
45             try
46             {
47                 Route route;
48 
49                 string cacheKey = request.header(HTTPHeaderCode.HOST) ~ "_" ~ request.method ~ "_" ~ request.path;
50                 route = this._cached.get(cacheKey, null);
51 
52                 if (route is null)
53                 {
54                     route = this._router.match(request.header(HTTPHeaderCode.HOST), request.method, request.path);
55 
56                     if (route is null)
57                     {
58                         request.createResponse().do404();
59                         
60                         return;
61                     }
62 
63                     this._cached[cacheKey] = route;
64                 }
65 
66                 // add route's params
67                 auto params = route.getParams();
68                 if (params.length > 0)
69                 {
70                     foreach (param, value; params)
71                     {
72                         request.Header().setQueryParam(param, value);
73                     }
74                 }
75 
76                 request.route = route;
77 
78 
79                 // hunt.security filter
80 				request.user = authenticateUser(request);
81 
82 				if (!accessFilter(request))
83 				{
84 					request.createResponse().do403("no permiss to access: " ~ request.route.getController() ~ "." ~ request.route.getAction() );
85 					return;
86 				}
87 
88                 // add handle task to taskPool
89                 this._taskPool.put(task!doRequestHandle(route.handle, request));
90             }
91             catch(Exception e)
92             {
93                 showException(e);
94             }
95         }
96 
97 		bool accessFilter(Request request)
98 		{
99 			//兼容老的.
100 			Identity identity =  Application.getInstance().getAccessManager().getIdentity(request.route.getGroup());
101 			if (identity is null || request.route.getController().length == 0)
102 				return true;
103 
104 
105 			return request.user.can(request.route.getController() ~ "." ~ request.route.getAction());
106 		}
107 
108 		User authenticateUser(Request request)
109 		{
110 			User user;
111 			Identity identity = Application.getInstance().getAccessManager().getIdentity(request.route.getGroup());
112 			if (identity !is null)
113 			{
114 				user = identity.login(request);
115 			}
116 
117 
118 			
119 			if (user is null)
120 			{
121 				return User.defaultUser;
122 			}
123 			
124 			return user;
125 		}
126 
127     
128 
129         void addRouteGroup(string group, string method, string value)
130         {
131             this._router.addGroup(group, method, value);
132         }
133 
134         void setWorkers(TaskPool taskPool)
135         {
136             this._taskPool = taskPool;
137         }
138 
139         void loadRouteGroups()
140         {
141             router.loadConfig();
142         }
143 
144         @property router()
145         {
146             return this._router;
147         }
148     }
149 
150     private
151     {
152         Router _router;
153         Route[string] _cached;
154         __gshared TaskPool _taskPool;
155     }
156 }
157 
158 void doRequestHandle(HandleFunction handle, Request request)
159 {
160     import hunt.http.exception;
161 
162     try
163     {
164         handle(request);
165     }
166     catch (CreateResponseException e)
167     {
168         showException(e);
169     }
170     catch (Exception e)
171     {
172         showException(e);
173         
174         Response response;
175 
176         collectException(request.createResponse, response);
177         
178         if(response)
179         {
180             collectException((){
181                     response.setHttpStatusCode(502);
182                     response.setContext(e.toString());
183                     response.connectionClose();
184                     response.done();
185                 }());
186         }
187     }
188     catch (Error e)
189     {
190         import std.stdio : writeln;
191 
192         collectException({logError(e.toString); writeln(e.toString());}());
193 
194         import core.stdc.stdlib : exit;
195 
196         exit(-1);
197     }
198 }